#ifndef _OPTION_TYPE_FILE_H_
#define _OPTION_TYPE_FILE_H_

#include <string>
#include <vector>
#include <istream>
#include <limits>

namespace inilib
{

	// ----------------------------------------------------------
	// Operators
	// ----------------------------------------------------------

	std::istream & operator>> ( std::istream & is, bool & value );
	std::istream & operator>> ( std::istream & is, short & value );
	std::istream & operator>> ( std::istream & is, int & value );
	std::istream & operator>> ( std::istream & is, long & value );
	std::istream & operator>> ( std::istream & is, long long & value );
	std::istream & operator>> ( std::istream & is, float & value );
	std::istream & operator>> ( std::istream & is, double & value );
	std::istream & operator>> ( std::istream & is, long double & value );
	std::istream & operator>> ( std::istream & is, std::string & value );

	std::istream & operator>> ( std::istream & is, unsigned short & value );
	std::istream & operator>> ( std::istream & is, unsigned int & value );
	std::istream & operator>> ( std::istream & is, unsigned long & value );
	std::istream & operator>> ( std::istream & is, unsigned long long & value );

	// ----------------------------------------------------------
	// Enums
	// ----------------------------------------------------------

	/**
	 * Is Option mandatory to be used in the ini file?
	 */
	enum Mandatory
	{
		/**
		 * Mandatory sections or options MUST be used (value(s) must be specified) in the ini file
		 * or it will not pass the validation step no matter what.
		 */
		MANDATORY,

		/**
		 * Nonmandatory sections or options may have value(s) specified in the ini file.
		 * Otherwise the default value(s) will be used (but it will pass the validation process).
		 */
		NONMANDATORY
	};

	/** How many values can option have. */
	enum ValuesAmount
	{
		/** Option can have only single value of the given type at the time. */
		SINGLE_VALUE,

		/** Option can have multiple values (or just one value) at the time. */
		MULTIPLE_VALUES
	};

	/**
	 * Basic class that represents all the information about particular option in ini file.
	 * It is meant to be inherited from so that each type can validate values as it see fit.
	 *
	 * Each OptionType is meant to be inserted into some section, but there is not class called Section.
	 * Instead it should be inserted directly into IniInfo class.
	 *
	 * Also it is important to note that this class receives all the necessary data on construction
	 * and doesn't have any methods that would allow to alter the state of the class. This is by design
	 * and is important because it is not possible to "mess with options" after they have been added
	 * to the IniInfo.
	 */
	class OptionType
	{
	public:

		/**
		 * OptionType obviously has to have a name that is unique in the given section.
		 * Separator is character that separates multiple values if they are allowed.
		 */
		explicit OptionType (
			const std::string & name,
			Mandatory isMandatory,
			ValuesAmount amount,
			char separator = ','
		);

		virtual ~OptionType ();

		std::string GetName () const;
		char GetSeparator () const;
		bool IsMandatory () const;
		
		/**
		 * Returns default value(s) for given option.
		 */
		virtual std::vector< std::string > GetDefaultValue () const = 0;

		/**
		 * Validates values against constraints defined in this option.
		 * Variable "totalValues" is here because it is not guaranteed that all values
		 * will be send in one pass (and that all of them are in vector "values" at the moment),
		 * but we still need to know their total count.
		 */
		bool AreValuesValid ( const std::vector< std::string > & values, unsigned int totalValues ) const;

	protected:

		/**
		 * Validates values against whatever criteria given type needs.
		 * It is important to know that this method may be called more then once for each option.
		 * Also it is not guaranteed that all values will be present in each pass (it is more likely
		 * that each time there will be a subset of all values).
		 */
		virtual bool AreValuesValid_ ( const std::vector< std::string > & values ) const = 0;

		std::string m_Name;
		Mandatory m_IsMandatory;
		ValuesAmount m_Amount;
		char m_Separator;
	};

}

#endif